use std::process::Stdio;
use std::sync::Arc;
use tokio::sync::Mutex;
use tokio::process::Command;
use serde::{Serialize, Deserialize};
use tracing::{info, error, debug};
use std::path::Path;

/// 转换进度信息
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct ConversionProgress {
    /// 总体进度(0-100)
    pub percentage: f32,
    /// 当前状态描述
    pub status: String,
    /// 已处理的瓦片数量
    pub processed_tiles: u32,
    /// 总瓦片数量
    pub total_tiles: Option<u32>,
    /// 预计剩余时间(秒)
    pub eta: Option<u32>,
    /// 是否完成
    pub completed: bool,
    /// 错误信息(如果有)
    pub error: Option<String>,
}

/// 瓦片转换服务
pub struct TileConversionService {
    /// PBF文件路径
    pbf_file_path: String,
    /// 瓦片输出目录
    output_dir: String,
    /// 最小缩放级别
    min_zoom: u8,
    /// 最大缩放级别
    max_zoom: u8,
    /// 是否包含道路
    include_roads: bool,
    /// 是否包含建筑物
    include_buildings: bool,
    /// 是否包含POI
    include_poi: bool,
    /// 是否包含水系
    include_water: bool,
    /// 是否包含土地利用
    include_landuse: bool,
    /// 是否包含行政边界
    include_boundaries: bool,
    /// 进度共享状态
    progress: Arc<Mutex<ConversionProgress>>,
    /// 最大并发任务数
    max_concurrent_tasks: usize,
}

impl TileConversionService {
    /// 创建新的瓦片转换服务实例
    pub fn new(
        pbf_file_path: String,
        output_dir: String,
        min_zoom: u8,
        max_zoom: u8,
        include_roads: bool,
        include_buildings: bool,
        include_poi: bool,
        include_water: bool,
        include_landuse: bool,
        include_boundaries: bool,
        progress: Arc<Mutex<ConversionProgress>>,
        max_concurrent_tasks: usize,
    ) -> Self {
        Self {
            pbf_file_path,
            output_dir,
            min_zoom,
            max_zoom,
            include_roads,
            include_buildings,
            include_poi,
            include_water,
            include_landuse,
            include_boundaries,
            progress,
            max_concurrent_tasks,
        }
    }

    /// 执行转换过程
    pub async fn convert(&self) -> Result<(), String> {
        // 验证PBF文件是否存在
        if !Path::new(&self.pbf_file_path).exists() {
            let err_msg = format!("PBF文件不存在: {}", self.pbf_file_path);
            self.update_progress(0.0, err_msg.clone(), 0, None, None, false, Some(err_msg.clone())).await;
            return Err(err_msg);
        }

        // 创建输出目录
        if let Err(e) = std::fs::create_dir_all(&self.output_dir) {
            let err_msg = format!("创建输出目录失败: {}", e);
            self.update_progress(0.0, err_msg.clone(), 0, None, None, false, Some(err_msg.clone())).await;
            return Err(err_msg);
        }

        info!(
            "开始转换PBF文件: {} 到瓦片, 缩放级别: {}-{}",
            self.pbf_file_path, self.min_zoom, self.max_zoom
        );

        // 计算总瓦片数量估算值
        let total_tiles = self.estimate_total_tiles();
        self.update_progress(0.0, "准备转换...".to_string(), 0, total_tiles, None, false, None).await;

        // 构建tilemaker命令
        let tilemaker_path = self.get_tilemaker_path()?;
        let config_path = self.get_config_path()?;
        
        // 构建命令参数
        let mut cmd = Command::new(&tilemaker_path);
        cmd.arg(&self.pbf_file_path)
            .arg("--output")
            .arg(&self.output_dir)
            .arg("--config")
            .arg(&config_path)
            .arg("--minzoom")
            .arg(self.min_zoom.to_string())
            .arg("--maxzoom")
            .arg(self.max_zoom.to_string())
            .stdout(Stdio::piped())
            .stderr(Stdio::piped());

        // 根据需要添加过滤参数
        let mut filters = Vec::new();
        if !self.include_roads {
            filters.push("roads");
        }
        if !self.include_buildings {
            filters.push("buildings");
        }
        if !self.include_poi {
            filters.push("poi");
        }
        if !self.include_water {
            filters.push("water");
        }
        if !self.include_landuse {
            filters.push("landuse");
        }
        if !self.include_boundaries {
            filters.push("boundaries");
        }

        // 添加过滤参数
        if !filters.is_empty() {
            cmd.arg("--exclude")
                .arg(filters.join(","));
        }

        debug!("执行tilemaker命令: {:?}", cmd);
        self.update_progress(5.0, "启动tilemaker进程...".to_string(), 0, total_tiles, None, false, None).await;

        // 执行命令并监控进度
        let mut child = cmd.spawn()
            .map_err(|e| format!("启动tilemaker失败: {}", e))?;

        // 提取stdout和stderr
        let stdout = child.stdout.take();
        let stderr = child.stderr.take();

        // 处理stdout和stderr
        let progress_clone = self.progress.clone();
        let total_tiles_clone = total_tiles;
        tokio::spawn(async move {
            if let Some(stdout) = stdout {
                Self::process_output(stdout, progress_clone, total_tiles_clone).await;
            }
        });

        tokio::spawn(async move {
            if let Some(stderr) = stderr {
                Self::process_errors(stderr).await;
            }
        });

        // 等待命令完成
        let status = child.wait().await
            .map_err(|e| format!("等待tilemaker完成失败: {}", e))?;

        if status.success() {
            info!("瓦片转换完成，输出目录: {}", self.output_dir);
            self.update_progress(100.0, "转换完成".to_string(), total_tiles.unwrap_or(0), total_tiles, Some(0), true, None).await;
            Ok(())
        } else {
            let err_msg = format!("tilemaker执行失败，退出码: {:?}", status.code());
            error!("{}", err_msg);
            self.update_progress(0.0, err_msg.clone(), 0, total_tiles, None, false, Some(err_msg.clone())).await;
            Err(err_msg)
        }
    }

    /// 处理命令输出以更新进度
    async fn process_output(
        mut stdout: tokio::process::ChildStdout,
        progress: Arc<Mutex<ConversionProgress>>,
        total_tiles: Option<u32>,
    ) {
        use tokio::io::{self, AsyncBufReadExt};
        let mut lines = io::BufReader::new(&mut stdout).lines();
        
        while let Ok(Some(line)) = lines.next_line().await {
            debug!("tilemaker输出: {}", line);
            
            // 尝试解析进度信息 (假设tilemaker输出包含类似"Processed 1234 tiles"的信息)
            if line.starts_with("Processed") && line.contains("tiles") {
                if let Some(count) = line.split_whitespace().nth(1) {
                    if let Ok(processed) = count.parse::<u32>() {
                        let percentage = if let Some(total) = total_tiles {
                            if total > 0 {
                                (processed as f32 / total as f32) * 100.0
                            } else {
                                0.0
                            }
                        } else {
                            // 如果无法获取总数，则估算进度
                            5.0 + (processed as f32 / 10000.0).min(95.0)
                        };
                        
                        let mut progress_lock = progress.lock().await;
                        progress_lock.percentage = percentage.min(100.0);
                        progress_lock.processed_tiles = processed;
                        progress_lock.status = format!("已处理 {} 个瓦片", processed);
                        
                        // 简单估算ETA
                        if let Some(total) = total_tiles {
                            if processed > 0 && total > processed {
                                // 这里只是简单示例，实际应根据处理速度计算
                                progress_lock.eta = Some(((total - processed) / processed.max(1)) * 5);
                            }
                        }
                    }
                }
            } else if line.starts_with("Error") {
                let mut progress_lock = progress.lock().await;
                progress_lock.status = "转换出错".to_string();
                progress_lock.error = Some(line.clone());
                error!("tilemaker错误: {}", line);
            } else if line.contains("Finished") {
                let mut progress_lock = progress.lock().await;
                progress_lock.percentage = 100.0;
                progress_lock.status = "转换完成".to_string();
                progress_lock.completed = true;
                progress_lock.eta = Some(0);
            }
        }
    }

    /// 处理错误输出
    async fn process_errors(mut stderr: tokio::process::ChildStderr) {
        use tokio::io::{self, AsyncBufReadExt};
        let mut lines = io::BufReader::new(&mut stderr).lines();
        
        while let Ok(Some(line)) = lines.next_line().await {
            error!("tilemaker错误输出: {}", line);
        }
    }

    /// 更新进度信息
    async fn update_progress(
        &self,
        percentage: f32,
        status: String,
        processed_tiles: u32,
        total_tiles: Option<u32>,
        eta: Option<u32>,
        completed: bool,
        error: Option<String>,
    ) {
        let mut progress = self.progress.lock().await;
        progress.percentage = percentage;
        progress.status = status;
        progress.processed_tiles = processed_tiles;
        progress.total_tiles = total_tiles;
        progress.eta = eta;
        progress.completed = completed;
        progress.error = error;
    }

    /// 获取tilemaker可执行文件路径
    fn get_tilemaker_path(&self) -> Result<String, String> {
        // 这里可以根据操作系统自动选择路径
        #[cfg(windows)]
        let default_path = "tilemaker/tilemaker.exe";
        #[cfg(unix)]
        let default_path = "tilemaker/tilemaker";

        // 检查tilemaker是否存在
        if !Path::new(default_path).exists() {
            return Err(format!(
                "tilemaker未找到，请确保它在路径: {}",
                default_path
            ));
        }

        Ok(default_path.to_string())
    }

    /// 获取tilemaker配置文件路径
    fn get_config_path(&self) -> Result<String, String> {
        let config_path = "tilemaker/config.json";
        
        if !Path::new(config_path).exists() {
            return Err(format!(
                "tilemaker配置文件未找到: {}",
                config_path
            ));
        }
        
        Ok(config_path.to_string())
    }

    /// 估算总瓦片数量
    fn estimate_total_tiles(&self) -> Option<u32> {
        // 简单估算不同缩放级别的瓦片数量
        // 实际应用中可以根据区域大小进行更准确的估算
        let mut total = 0;
        for zoom in self.min_zoom..=self.max_zoom {
            let tiles_at_zoom = 4u32.pow(zoom as u32);
            // 中国区域大约占全球的1/10
            total += tiles_at_zoom / 10;
        }
        Some(total)
    }
}
